use axum::{extract::State, routing::post, Extension, Form, Json, Router};
use axum_app_common::{
    error::BizError,
    model::{AppState, BizRequest, BizResponse, RequestForm, SessionContext},
    ServiceStore,
};
use serde_json::Value;
use std::sync::Arc;
use tracing::{error, info};

/// API 网关的router入口方法
pub fn router(fn_map: Arc<ServiceStore>) -> Router<AppState> {
    let fn_map_shared = Arc::clone(&fn_map);
    let api_routes = Router::new().route(
        "/gateway",
        post(
            |State(state): State<AppState>,
             Extension(session): Extension<SessionContext>,
             Form(form): Form<RequestForm>| {
                async move {
                    info!("session info: {:?}", session);

                    let request = BizRequest::from_form(form, Some(session), Some(state));

                    if request.is_err() {
                        error!(
                            "[request 转换异常] {}",
                            request.as_ref().err().unwrap().to_string()
                        );
                        let err_msg = request.err().unwrap();
                        return Json(
                            BizResponse::<String>::fail_with_biz_error(
                                BizError::InvalidParams(None),
                                Some(err_msg.as_str()),
                            )
                            .to_json_value(),
                        );
                    }

                    let request = request.unwrap();
                    let service = request.get_service();

                    let fnuc_opt = fn_map_shared.get_func(service);

                    let Some(fnuc) = fnuc_opt else {
                        return Json(
                            BizResponse::<Value>::fail_with_biz_error(
                                BizError::ServiceNotFound,
                                None,
                            )
                            .to_json_value(),
                        );
                    };

                    let resp_result = fnuc(request).await;

                    let biz_resp = match resp_result {
                        Ok(resp) => resp,
                        Err(err) => except_handler(err),
                    };

                    Json(biz_resp.to_json_value())
                }
            },
        ),
    );

    api_routes
}

// 异常/错误处理
fn except_handler(err: anyhow::Error) -> BizResponse<Value> {
    if let Some(biz_err) = err.downcast_ref::<BizError>() {
        return BizResponse::<Value>::fail_with_biz_error_ref(biz_err, None);
    }

    let err_msg = err.to_string();
    error!("[非预知异常] {}", err_msg);
    BizResponse::<Value>::fail_with_biz_error(BizError::Unknown, Some(&err_msg))
}

/// 注册业务处理方法的地方
pub fn regist_handlers() -> ServiceStore {
    let mut store = ServiceStore::new();

    // 注册handler
    store.add_service_store(axum_app_service::service_map());

    store
}
